package common.stack.delayStack.two;

import common.stack.delayStack.DelayedQueue;

public class MyQueue<E> implements DelayedQueue<E> {

    class QueueNode<E> {
        private E data;
        private QueueNode<E> next;

        public QueueNode(E data, QueueNode<E> next) {
            this.data = data;
            this.next = next;
        }
    }

    public QueueNode<E> head;
    public QueueNode<E> tail;
    private int size;
    private int maximumDelay;
    private int delay;
    private boolean dequeue;

    public MyQueue(int maximumDelay) {
        this.tail = null;
        this.head = null;
        this.size = 0;
        this.maximumDelay = maximumDelay;
        this.delay = maximumDelay;
        this.dequeue = false;
    }

    public int size() {
        return size;
    }

    public void enqueue(E element) {
        QueueNode<E> node = new QueueNode<>(element, null);
        if (head == null) {
            head = node;
            tail = head;
        } else {
            tail.next = node;
            tail = node;
        }

        if (dequeue && delay <= 0) {
            this.dequeue = false;
            this.delay = this.maximumDelay;
        }
        this.delay--;
        this.size++;

    }

    public E dequeue() throws IllegalStateException {
        if (size == 0) {
            throw new IllegalStateException();
        }else if (delay > 0) {
            return null;
        } else {
            E data = head.data;
            head = head.next;
            size--;
            dequeue = true;
            return data;
        }
    }

    public E peek() throws IllegalStateException {
        if (size == 0) {
            throw new IllegalStateException();
        } else {
            return head.data;
        }
    }

    public int getDelay() {
        return Math.max(delay, 0);
    }

    public void setMaximumDelay(int d) {
        this.maximumDelay = d;
    }

    public int getMaximumDelay() {
        return maximumDelay;
    }

    public boolean clear() {
        if (delay <= 0) {
            this.head = null;
            this.tail = null;
            this.size = 0;
            this.dequeue = true;
        }
        return delay <= 0;
    }

    public boolean contains(E elem) {
        QueueNode<E> node = head;
        while (node != null) {
            E data = node.data;
            if (data == null && elem == null) {
                return true;
            } else if (data != null && data.equals(elem)) {
                return true;
            } else if (elem != null && elem.equals(data)) {
                return true;
            }

            node = node.next;
        }
        return false;
    }

}